<template>
  <div class="spu-content">
    <div ref="threeRef" class="threeRef"></div>
  </div>
</template>

<script lang="ts" setup>
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 导入 lil.gui
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
import { onMounted, ref } from 'vue'

const threeRef = ref()
//创建场景
const scene = new THREE.Scene()
// scene.background = new THREE.Color(0xc89e06b)
//创建透视投影相机，视角45度，画幅比例 宽比高，近平面距离0.1，远平面1000
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1, // 近平面
  1000, // 远平面
)
//创建渲染器
const renderer = new THREE.WebGLRenderer()

//定义一个几何体
const geometry = new THREE.BoxGeometry(1, 1, 1)
// const geometry = new THREE.CylinderGeometry(3, 30, 40)
//定义一种材质，显示为线框
const material = new THREE.MeshBasicMaterial({
  color: 0xb3dd,
  wireframe: true, // 线框模式
})
// 定义一个材质
const parentMaterial = new THREE.MeshBasicMaterial({
  color: 0xff0000,
  wireframe: true, // 线框模式
})
//网孔(Mesh)是用来承载几何模型的一个对象，可以把材料应用到它上面
const ball = new THREE.Mesh(geometry, material)
ball.position.set(3, 0, 0)
// 定义一个父元素
const parentBall = new THREE.Mesh(geometry, parentMaterial)
parentBall.position.set(-3, 0, 0)
// 将子元素放到父元素中
parentBall.add(ball)

// 设置物体的放大
ball.scale.set(2, 2, 2)
// 设置物体的旋转 可规定旋转顺序 (xyz) 也是相对于父元素
ball.rotation.x = Math.PI / 4

//把几何模型添加到场景中，对象被添加到原点(0,0,0)坐标。
scene.add(parentBall)

//移动相机位置
camera.position.z = 8
camera.position.x = 5
camera.position.y = 3
camera.lookAt(0, 0, 0)

// 添加世界坐标辅助器
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)

// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 设置带阻尼的惯性
controls.enableDamping = true
// 设置阻尼系数
controls.dampingFactor = 0.05
// 设置旋转速度
// controls.autoRotate = true

const render = () => {
  controls.update()
  //渲染循环，以每秒60次的频率来绘制场景
  requestAnimationFrame(render)
  //设置球体绕y轴旋转
  // ball.rotation.y += 0.005
  // ball.rotation.x += 0.005
  renderer.render(scene, camera)
}

const eventObj = {
  Fullscreen: () => {
    document.body.requestFullscreen()
  },
  ExitFullscreen: () => {
    document.exitFullscreen()
  },
}

// 创建 GUI
const gui = new GUI()
// 添加按钮
gui.add(eventObj, 'Fullscreen').name('全屏')
gui.add(eventObj, 'ExitFullscreen').name('退出全屏')
// 控制立方体位置
// gui.add(ball.position, 'x', -5, 5).name('立方体x轴位置')
// 创建控制器文件夹(用来分组) onChange 移动触发 onFinishChange 移动完成触发
const folder = gui.addFolder('立方体位置')
folder
  .add(ball.position, 'x')
  .min(-10)
  .max(10)
  .step(1)
  .name('立方体X轴位置')
  .onChange((val) => {
    console.log('立方体X轴位置', val)
  })
folder
  .add(ball.position, 'y')
  .min(-10)
  .max(10)
  .step(1)
  .name('立方体Y轴位置')
  .onFinishChange((val) => {
    console.log('立方体Y轴位置', val)
  })
folder.add(ball.position, 'z').min(-10).max(10).step(1).name('立方体Z轴位置')
// 控制器的线框模式
gui.add(parentMaterial, 'wireframe').name('父元素线框模式')
// 控制器父元素的颜色
const colorParams = {
  parentColor: '#ff0000',
}
gui
  .addColor(colorParams, 'parentColor')
  .name('父元素的颜色11')
  .onChange((val) => {
    parentBall.material.color.set(val)
  })

onMounted(() => {
  //渲染器canvas宽高设为与窗口一致
  renderer.setSize(threeRef.value.clientWidth, threeRef.value.clientHeight)
  //将渲染器对应的dom元素添加到body中
  threeRef.value.appendChild(renderer.domElement)
  render()
})

// 监听窗口变化
window.addEventListener('resize', () => {
  // 重置渲染器宽高
  renderer.setSize(threeRef.value.clientWidth, threeRef.value.clientHeight)
  // 重置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight
  // 更新相机投影矩阵
  camera.updateProjectionMatrix()
})
</script>

<style lang="scss" scoped>
.spu-content {
  width: 100vw;
  height: 100vh;
  .threeRef {
    width: 100%;
    height: 100%;
  }
}
</style>
